package websocket_plugin

import (
	"context"
	"gitee.com/kristas/booting-go/framework/core/bean"
	"gitee.com/kristas/booting-go/framework/core/statement/types"
	"gitee.com/kristas/booting-go/framework/web"
	"gitee.com/kristas/booting-go/framework/web/rest"
	"github.com/gorilla/websocket"
	"net/http"
	"time"
)

// WebsocketHandler bean define
type WebsocketHandler interface {
	bean.Bean
	Endpoint() string
	OnOpen(session *Session)
	OnClose(session *Session)
	OnMessage(session *Session, message []byte) error
	OnError(session *Session, err error)
}

// WebsocketConfig is websocket config
type WebsocketConfig struct {
	types.AutoConfigure `prefix:"websocket"`
	WriteWait           time.Duration `yaml:"write_wait"`         // Time allowed to write a message to the peer.
	MaxMessageSize      int64         `yaml:"max_message_size"`   // Maximum message size allowed from peer.
	PongWait            time.Duration `yaml:"pong_wait"`          // Time allowed to read the next pong message from the peer.
	PingPeriod          time.Duration `yaml:"ping_period"`        // Send pings to peer with this period. Must be less than pongWait.
	CloseGracePeriod    time.Duration `yaml:"close_grace_period"` // Time to wait before force close on connection.
	CheckOrigin         bool          `yaml:"check_origin"`
}

// WebsocketController is decorate dynamic controller
type WebsocketController struct {
	types.Component
	handler WebsocketHandler
	channel rest.GET `url:"" param:"[r request,w response]"`
	Config  *WebsocketConfig
}

func newWsController(handler WebsocketHandler) web.Controller {
	return &WebsocketController{handler: handler}
}

func (w *WebsocketController) Bean() string {
	return w.handler.Bean()
}

func (w *WebsocketController) Group() string {
	return w.handler.Endpoint()
}

func (w *WebsocketController) Channel(r *http.Request, rw http.ResponseWriter) {
	newWsHelper(*w.Config, w.handler).serve(r, rw)
}

type Session struct {
	*websocket.Conn
	HttpSession *http.Request
	Context     context.Context
	value       map[string]interface{}
}

func newSession(conn *websocket.Conn, request *http.Request) *Session {
	return &Session{Conn: conn, HttpSession: request, value: make(map[string]interface{})}
}

func (s *Session) Set(key string, value interface{}) {
	s.value[key] = value
}

func (s *Session) Get(key string) (interface{}, bool) {
	if v, ok := s.value[key]; ok {
		return v, ok
	}
	return nil, false
}
